#ifndef _DISPLAYABLE_H_
#define _DISPLAYABLE_H_

#ifdef _WIN32
#pragma once
#endif

/**
 * 1.4.12 - Steven Hartin - Added bounding data into the displayable object.
 *
 * 17.3.12 - Steven Hartin - Added the ability to not render certain subsets
 *
 * 16.3.12 - Steven Hartin - Added the ability to add animation files.
 *
 * 04/03/12 - Steven Hartin / Stephen Gore - Original creation. Most of this
 *      was programmed by Stephen Gore in mesh.cpp and copied / altered by
 *      Steven Hartin. Added lots more getters / setters.
 *
 * This displayable object just contains a specific instance of a mesh and
 * some transformations with the ability to render at a specific location / 
 * size. The reason this functionality is not within the mesh object is incase
 * we want multiple instances of the mesh object to be rendered at different
 * locations. Without copying the mesh data, it is not possible to obtain this.
 * Therefore, splitting out the functionality to two classes allows us to
 * have a reference to a mesh, whilst having unique transformation data.
 */
class CDisplayable;

#include <string>
#include <sstream>
#include <set>

#include <d3dx9.h>

#include "meshcontainer.h"
#include "mesh.h"
#include "devicemanager.h"
#include "timer.h"
#include "displayablecontainer.h"
#include "camera.h"

using std::string;
using std::stringstream;
using std::set;
using std::map;

class CDisplayable
{
public:
    // Constructor.
    CDisplayable();  
    CDisplayable(CMesh *pMesh);
    CDisplayable(const string &szKeyname);

    // Destuctor.
    ~CDisplayable();                         

    // Load Animation
    void loadAnimation(const string &szFileName);
    void setAnimationSet(int nCurrentAnimationSet);
    int getCurrentAnimationSet() const;

    // Mesh settings
    void assignMesh(CMesh *pMesh);
    void setMaterial(CMaterial Material, DWORD dwSubset);
    void setTexture(CTexture* texture, DWORD dwSubset);

    // Transformations
    void setXTranslate(float x);
    void setYTranslate(float y);
    void setZTranslate(float z);
    void setTranslate(float x, float y, float z);
    float getTranslateX() const;
    float getTranslateY() const;
    float getTranslateZ() const;
    void getTranslate(float &x, float &y, float &z);

    // All values are returned / set in degrees
    void setXRotate(float x);
    void setYRotate(float y);
    void setZRotate(float z);
    void setRotate(float x, float y, float z);
    float getRotateX() const;
    float getRotateY() const;
    float getRotateZ() const;
    void getRotate(float &x, float &y, float &z);

    void setXScale(float x);
    void setYScale(float y);
    void setZScale(float z);
    void setScale(float x, float y, float z);
    float getScaleX() const;
    float getScaleY() const;
    float getScaleZ() const;
    void getScale(float &x, float &y, float &z);

    /*void setXVelocity(float amount);
    void setYVelocity(float amount);
    void setZVelocity(float amount);
    void setVelocitiy(float x, float y, float z);
    float getXVelocitiy() const;
    float getYVelocitiy() const;
    float getZVelocitiy() const;
    void getVelocity(float &x, float &y, float &z);*/

    void render();    

    // Visibility
    bool isVisible() const;
    void show();
    void hide();
    void setVisible(bool bVisible);

    bool hasMaterial(DWORD nSubset) const;
    const CMaterial& getMaterial(DWORD nSubset) const;

    bool hasTexture(DWORD nSubset) const;
    CTexture *getTexture(DWORD nSubset) const;

    void setSubsetNonDrawable(DWORD nSubset);
    bool isSubsetDrawable(DWORD nSubset) const;
    void setSubsetDrawable(DWORD nSubset);

    TBoundingShape getBoundingShape() const;

    void showBoundingBox();
    void hideBoundingBox();

    void setAutomaticallyRendered(bool bAutomaticallyRendered);
    bool canBeAutomaticallyRendered() const;

private:
    // Mesh.
    CMesh *m_pMesh;

    // list of Materials.
    map<DWORD,CMaterial> m_arrMeshMaterials;

    // List of Textures.
    map<DWORD,CTexture*> m_arrMeshTextures;

    // List of non-drawable subsets
    set<DWORD> m_arrNonDrawables;

    // Transformations.
    float m_fRotateX;
    float m_fRotateY;
    float m_fRotateZ;
    
    float m_fTranslateX;
    float m_fTranslateY;
    float m_fTranslateZ;

    float m_fScaleX;
    float m_fScaleY;
    float m_fScaleZ;

    float m_fVelocityX;
    float m_fVelocityY;
    float m_fVelocityZ;

    // Visibility
    bool m_bVisible;
    bool m_bShowBoundingBox;

    bool m_bAutomaticallyRendered;

    // Animation ID
    int m_nAnimationID;
    int m_nCurrentAnimationSet;
    bool m_bResetAnimationFrameTime;

    // Animation time.
    CTimer m_LastFrameTime;

    TBoundingShape m_BoundingShape;

    void _updateBoundingData(const D3DXMATRIX &matWorld);
};

#endif